/*
 * Copyright (c) 2025 CAX Conversion Project
 */
package com.comac.ins.isfd.service.impl;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.comac.ins.common.core.constant.CommonConstant;
import com.comac.ins.common.core.exception.base.BaseException;
import com.comac.ins.common.core.utils.MapstructUtils;
import com.comac.ins.common.mybatis.core.page.PageQuery;
import com.comac.ins.common.mybatis.core.page.TableDataInfo;
import com.comac.ins.isfd.domain.IsfdDatabaseDataImportRecord;
import com.comac.ins.isfd.domain.bo.IsfdDatabaseDataImportRecordBo;
import com.comac.ins.isfd.domain.bo.IsfdDatabaseModelingConfigSaveBo;
import com.comac.ins.isfd.domain.vo.IsfdDatabaseModelingConfigFieldVo;
import com.comac.ins.isfd.domain.vo.IsfdDatabaseModelingConfigShowVo;
import com.comac.ins.isfd.service.IIsfdDatabaseDynamicMongoService;
import com.comac.ins.isfd.util.ParseBDFUtils;
import com.comac.ins.isfd.util.TableNameGenerator;
import com.comac.ins.system.service.ISysDictDataService;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.comac.ins.isfd.domain.bo.IsfdDatabaseModelingConfigBo;
import com.comac.ins.isfd.domain.vo.IsfdDatabaseModelingConfigVo;
import com.comac.ins.isfd.domain.IsfdDatabaseModelingConfig;
import com.comac.ins.isfd.mapper.IsfdDatabaseModelingConfigMapper;
import com.comac.ins.isfd.service.IIsfdDatabaseModelingConfigService;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.web.multipart.MultipartFile;
import software.amazon.awssdk.services.s3.endpoints.internal.Value;

import java.nio.file.Path;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 数据库建模配置Service业务层处理
 *
 * @author Lion Li
 * @date 2024-11-27
 */
@RequiredArgsConstructor
@Service
@Slf4j
public class IsfdDatabaseModelingConfigServiceImpl implements IIsfdDatabaseModelingConfigService {

    @Autowired
    private final IsfdDatabaseModelingConfigMapper baseMapper;

    @Autowired
    private IIsfdDatabaseDynamicMongoService mongoService;

    @Autowired
    private ISysDictDataService iSysDictDataService;

    @Autowired
    private IsfdDatabaseDataImportRecordServiceImpl importRecordService;

    /**
     * 查询数据库建模配置
     *
     * @param id 主键
     * @return 数据库建模配置
     */
    @Override
    public IsfdDatabaseModelingConfigVo queryById(String id){
        return baseMapper.selectVoById(id);
    }

    /**
     * 分页查询数据库建模配置列表
     *
     * @param bo        查询条件
     * @param pageQuery 分页参数
     * @return 数据库建模配置分页列表
     */
    @Override
    public TableDataInfo<IsfdDatabaseModelingConfigVo> queryPageList(IsfdDatabaseModelingConfigBo bo, PageQuery pageQuery) {
        LambdaQueryWrapper<IsfdDatabaseModelingConfig> lqw = buildQueryWrapper(bo);
        Page<IsfdDatabaseModelingConfigVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
        return TableDataInfo.build(result);
    }

    /**
     * 查询符合条件的数据库建模配置列表
     *
     * @param bo 查询条件
     * @return 数据库建模配置列表
     */
    @Override
    public List<IsfdDatabaseModelingConfigShowVo> queryList(IsfdDatabaseModelingConfigBo bo) {

        LambdaQueryWrapper<IsfdDatabaseModelingConfig> lqw = buildQueryWrapper(bo);
        List<IsfdDatabaseModelingConfig> configList = baseMapper.selectList(lqw);
        if (CollectionUtils.isEmpty(configList)) {
            throw new BaseException("未查询到相关数据库模型配置！");
        }
        Map<String, List<IsfdDatabaseModelingConfig>> groupedMap = configList.stream().collect(Collectors.groupingBy(IsfdDatabaseModelingConfig::getTableName));
        List<IsfdDatabaseModelingConfigShowVo> showVoList = groupedMap.entrySet().stream()
            .map(entry -> {
                IsfdDatabaseModelingConfigShowVo showVo = MapstructUtils.convert(entry.getValue().get(0), IsfdDatabaseModelingConfigShowVo.class);
                List<IsfdDatabaseModelingConfigFieldVo> fieldVoList = entry.getValue().stream()
                    .map(po -> MapstructUtils.convert(po, IsfdDatabaseModelingConfigFieldVo.class)).toList();
                showVo.setFieldList(fieldVoList);
                return showVo;
            }).toList();
        return showVoList;
    }

    @Override
    public List<IsfdDatabaseModelingConfigFieldVo> queryFieldsByTableName(String tableName) {
        IsfdDatabaseModelingConfigBo bo = new IsfdDatabaseModelingConfigBo();
        bo.setTableName(tableName);
        LambdaQueryWrapper<IsfdDatabaseModelingConfig> lqw = buildQueryWrapper(bo);
        List<IsfdDatabaseModelingConfig> configList = baseMapper.selectList(lqw);
        List<IsfdDatabaseModelingConfigFieldVo> fieldVoList = configList.stream()
            .map(config -> MapstructUtils.convert(config, IsfdDatabaseModelingConfigFieldVo.class)).toList();
        return fieldVoList;
    }

    private LambdaQueryWrapper<IsfdDatabaseModelingConfig> buildQueryWrapper(IsfdDatabaseModelingConfigBo bo) {
        Map<String, Object> params = bo.getParams();
        LambdaQueryWrapper<IsfdDatabaseModelingConfig> lqw = Wrappers.lambdaQuery();
        lqw.eq(StringUtils.isNotBlank(bo.getModelName()), IsfdDatabaseModelingConfig::getModelName, bo.getModelName());
        lqw.eq(StringUtils.isNotBlank(bo.getBusinessScenario()), IsfdDatabaseModelingConfig::getBusinessScenario, bo.getBusinessScenario());
        lqw.eq(StringUtils.isNotBlank(bo.getBusinessSystem()), IsfdDatabaseModelingConfig::getBusinessSystem, bo.getBusinessSystem());
        lqw.eq(StringUtils.isNotBlank(bo.getDatabaseType()), IsfdDatabaseModelingConfig::getDatabaseType, bo.getDatabaseType());
        lqw.eq(StringUtils.isNotBlank(bo.getDatabaseSubtype()), IsfdDatabaseModelingConfig::getDatabaseSubtype, bo.getDatabaseSubtype());
        lqw.eq(StringUtils.isNotBlank(bo.getTableName()), IsfdDatabaseModelingConfig::getTableName, bo.getTableName());
        lqw.like(StringUtils.isNotBlank(bo.getTableDescription()), IsfdDatabaseModelingConfig::getTableDescription, bo.getTableDescription());
        lqw.eq(StringUtils.isNotBlank(bo.getFieldName()), IsfdDatabaseModelingConfig::getFieldName, bo.getFieldName());
        lqw.like(StringUtils.isNotBlank(bo.getFieldDescription()), IsfdDatabaseModelingConfig::getFieldDescription, bo.getFieldDescription());
        lqw.eq(StringUtils.isNotBlank(bo.getFieldType()), IsfdDatabaseModelingConfig::getFieldType, bo.getFieldType());
        lqw.eq(StringUtils.isNotBlank(bo.getFieldStructure()), IsfdDatabaseModelingConfig::getFieldStructure, bo.getFieldStructure());
        lqw.eq(IsfdDatabaseModelingConfig::getIsDelete, 0);
        return lqw;
    }

    @Override
    public Boolean saveConfig(IsfdDatabaseModelingConfigSaveBo saveBo){
        // 判断新增还是修改
        IsfdDatabaseModelingConfigBo queryBo = MapstructUtils.convert(saveBo, IsfdDatabaseModelingConfigBo.class);
        queryBo.setTableDescription(null);
        LambdaQueryWrapper<IsfdDatabaseModelingConfig> lqw = buildQueryWrapper(queryBo);
        List<IsfdDatabaseModelingConfig> existConfigList = baseMapper.selectList(lqw);
        if (!CollectionUtils.isEmpty(existConfigList) && StringUtils.isNotBlank(saveBo.getTableName())) {
            // 修改
            baseMapper.deleteBatchIds(existConfigList);
        }
        // 根据传入参数生成表名
        List<String> fields = new ArrayList<>();
        fields.add(saveBo.getBusinessScenario());
        fields.add(saveBo.getBusinessSystem());
        fields.add(saveBo.getDatabaseType());
        fields.add(saveBo.getDatabaseSubtype());
        fields.add(saveBo.getModelName());
        String tableName = TableNameGenerator.generatePinyinTableName(fields);
        // 保存配置
        List<IsfdDatabaseModelingConfig> configList = new ArrayList<>();
        saveBo.getFieldList().forEach(fieldBo -> {
            IsfdDatabaseModelingConfig configPo = MapstructUtils.convert(fieldBo, IsfdDatabaseModelingConfig.class);
            MapstructUtils.convert(saveBo, configPo);
            configPo.setTableName(tableName);
            configList.add(configPo);
            });
        return baseMapper.insertBatch(configList);
    }

    @Override
    public Integer deleteConfig(IsfdDatabaseModelingConfigBo bo) {
        if (StringUtils.isEmpty(bo.getTableName())) {
            throw new BaseException("表名不能为空！");
        }
        LambdaQueryWrapper<IsfdDatabaseModelingConfig> lqw = buildQueryWrapper(bo);
        List<IsfdDatabaseModelingConfig> existConfigList = baseMapper.selectList(lqw);
        return baseMapper.deleteBatchIds(existConfigList);
    }

    @Transactional
    @Override
    public String importBDFData(IsfdDatabaseModelingConfigBo bo, MultipartFile file) {
        // 校验建模表中是否存在该表信息
        String tableName = bo.getTableName();
        if (StringUtils.isBlank(tableName)) {
            log.error("未配置导入位置！");
            throw new BaseException("未配置导入位置！");
        }
        List<IsfdDatabaseModelingConfigFieldVo> fieldVoList = this.queryFieldsByTableName(tableName);
        if (CollectionUtils.isEmpty(fieldVoList)) {
            log.error("未查询到相关数据表配置信息！");
            throw new BaseException("未查询到相关数据表配置信息！");
        }
        // 将 List 转换为 Map，以 fieldName 作为 key
        Map<String, IsfdDatabaseModelingConfigFieldVo> fieldVoMap = fieldVoList.stream()
            .collect(Collectors.toMap(
                IsfdDatabaseModelingConfigFieldVo::getFieldName, // key 提取器
                field -> field)); // value 提取器
        // pyNastran解析bdf文件
        String bdfImportDir = iSysDictDataService.selectDictValueByTypeAndLabel(CommonConstant.SYS_COMMON_DICT_TYPE, CommonConstant.DATA_IMPORT_RECORD_BDF_FILE_PATH);
        Path importFilePath = ParseBDFUtils.saveImportFile(bdfImportDir, file);
        Map<String, List<Map<String, Object>>> importMaterials = ParseBDFUtils.parseMaterialBDF(importFilePath);
        if (CollectionUtils.isEmpty(importMaterials)) {
            throw new BaseException("文件解析失败！");
        }
        // 获取字段映射配置, 通过表名获取
        String matType = iSysDictDataService.selectDictValueByTypeAndLabel(CommonConstant.TABLE_TO_BDF_TYPE_MAPPING, tableName);
        String fieldsMapJsonString = iSysDictDataService.selectDictValueByTypeAndLabel(CommonConstant.BDF_PARSING_FIELDS_MAP, matType);
        Map<String, String> fieldMappings = parseFieldMappings(fieldsMapJsonString);// 转换字段映射为 Map
        if (CollectionUtils.isEmpty(fieldMappings)) {
            throw new BaseException("未找到相关bdf模板配置！");
        }
        // 根据材料类型筛选要导入的数据
        if(!importMaterials.containsKey(matType)){
            throw new BaseException("bdf文件中没有相关材料数据，材料类型：" + matType);
        }
        List<Map<String, Object>> matchedMaterials = importMaterials.get(matType);

        int successCount = 0;
        // 遍历符合条件的材料数据
        for (Map<String, Object> matchedMaterial : matchedMaterials) {
            boolean valid = true;
            Map<String, Object> processedMaterial = new HashMap<>();
            // 校验并转换所有字段
            for (Map.Entry<String, String> entry : fieldMappings.entrySet()) {
                String tableField = entry.getKey();
                String bdfField = entry.getValue();
                // 获取值
                Object value = matchedMaterial.get(bdfField);
                // 校验非空
                if (fieldVoMap.get(tableField).getIsNullable() == 0 && value == null) {
                    if (fieldVoMap.get(tableField).getDefaultValue() == null) {
                        log.warn("字段：" + tableField + "必须有值，文件中该条数据无值: "+ matchedMaterial);
                        valid = false;
                        break;
                    }
                    value = fieldVoMap.get(tableField).getDefaultValue();
                }
                // 校验和转换数据类型
                String valueType = fieldVoMap.get(tableField).getFieldType();
                try {
                    value = convertToType(value, valueType); // 转换数据类型
                } catch (Exception e) {
                    log.error("字段：" + tableField + " 数据类型校验失败，值：" + value + "，期望类型：" + valueType, e);
                    valid = false; // 数据无效
                    break; // 跳出字段校验
                }
                // 添加属性
                processedMaterial.put(tableField, value);
            }
            // 如果数据无效，跳过当前记录
            if (!valid) {continue;}
            // 将数据保存到mongoDB
            Boolean success = mongoService.save(tableName, processedMaterial);
            if (success){
                successCount++;
            }
        }
        // 插入记录
        saveImportRecord(bo, successCount, importFilePath);
        return "成功插入" + successCount + "条数据";
    }

    private void saveImportRecord(IsfdDatabaseModelingConfigBo bo, Integer successCount, Path importFilePath) {
        IsfdDatabaseDataImportRecordBo importRecordBo = new IsfdDatabaseDataImportRecordBo();
        importRecordBo.setBusinessScenario(bo.getBusinessScenario());
        importRecordBo.setBusinessSystem(bo.getBusinessSystem());
        importRecordBo.setDatabaseType(bo.getDatabaseType());
        importRecordBo.setDatabaseSubtype(bo.getDatabaseSubtype());
        importRecordBo.setModelName(bo.getModelName());
        importRecordBo.setTableName(bo.getTableName());
        importRecordBo.setDataImportTime(bo.getCreateTime());
        importRecordBo.setDataQuantity(successCount);
        importRecordBo.setDataFileUrl(importFilePath.toAbsolutePath().toString());
        importRecordService.insertByBo(importRecordBo);
    }

    private Map<String, String> parseFieldMappings(String jsonString) {
        ObjectMapper objectMapper = new ObjectMapper();
        try {
            // 解析 JSON 字符串为 Map<String, String>
            return objectMapper.readValue(jsonString, new TypeReference<>() {
            });
        } catch (Exception e) {
            return Collections.emptyMap();  // 解析失败时返回空列表
        }
    }

    private Object convertToType(Object value, String valueType) throws Exception {
        if (value == null) {
            return null;
        }
        switch (valueType.toLowerCase()) {
            case "string":
                return value.toString();
            case "integer":
                return Integer.parseInt(value.toString());
            case "double":
                return Double.parseDouble(value.toString());
            case "long":
                return Long.parseLong(value.toString());
            default:
                throw new Exception("不支持的数据类型: " + valueType + ", (支持类型：string，integer，double，long)");
        }
    }




}
